all repos — caroster @ d0d47704e427face6c4cea5a2e1326c3679f6f5d

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/waitingList.tsx (view raw)

  1import {useState, useEffect, useMemo} from 'react';
  2import {makeStyles} from '@material-ui/core/styles';
  3import {useTranslation} from 'react-i18next';
  4import {initializeApollo} from '../../../lib/apolloClient';
  5import useToastStore from '../../../stores/useToastStore';
  6import useEventStore from '../../../stores/useEventStore';
  7import Layout from '../../../layouts/Default';
  8import {Travel as TravelType} from '../../../generated/graphql';
  9import EventBar from '../../../containers/EventBar';
 10import Loading from '../../../containers/Loading';
 11import {
 12  useUpdateEventMutation,
 13  Event as EventType,
 14  useEventByUuidQuery,
 15  EventByUuidDocument,
 16  EditEventInput,
 17  useFindUserVehiclesQuery,
 18} from '../../../generated/graphql';
 19import ErrorPage from '../../_error';
 20import useProfile from '../../../hooks/useProfile';
 21import useBannerStore from '../../../stores/useBannerStore';
 22import DrawerMenu from '../../../containers/DrawerMenu';
 23import WaitingList from '../../../containers/WaitingList';
 24import {
 25  AddPassengerToTravel,
 26  AddPassengerToWaitingList,
 27} from '../../../containers/NewPassengerDialog';
 28import AddToMyEventDialog from '../../../containers/AddToMyEventDialog';
 29
 30const POLL_INTERVAL = 10000;
 31
 32interface NewPassengerDialogContext {
 33  addSelf: boolean;
 34}
 35
 36interface Props {
 37  event: EventType;
 38  eventUUID: string;
 39}
 40
 41const EventPage = props => {
 42  const {t} = useTranslation();
 43  const {event} = props;
 44  if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
 45  return <Event {...props} />;
 46};
 47
 48const Event = (props: Props) => {
 49  const {eventUUID} = props;
 50  const bannerOffset = useBannerStore(s => s.offset);
 51  const classes = useStyles({bannerOffset});
 52  const {t} = useTranslation();
 53  const {user} = useProfile();
 54  const {data: {me: {profile: {vehicles = []} = {}} = {}} = {}, loading} =
 55    useFindUserVehiclesQuery();
 56  const addToast = useToastStore(s => s.addToast);
 57  const setEvent = useEventStore(s => s.setEvent);
 58  const eventUpdate = useEventStore(s => s.event);
 59  const setIsEditing = useEventStore(s => s.setIsEditing);
 60  const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
 61  const [addPassengerToWaitingListContext, toggleNewPassengerToWaitingList] =
 62    useState<NewPassengerDialogContext | null>(null);
 63  const [updateEvent] = useUpdateEventMutation();
 64  const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
 65    pollInterval: POLL_INTERVAL,
 66    variables: {uuid: eventUUID},
 67  });
 68
 69  useEffect(() => {
 70    if (event) setEvent(event as EventType);
 71  }, [event]);
 72
 73  const onSave = async e => {
 74    try {
 75      const {uuid, ...data} = eventUpdate;
 76      const {id, __typename, travels, users, waitingList, ...input} = data;
 77      await updateEvent({
 78        variables: {uuid, eventUpdate: input as EditEventInput},
 79        refetchQueries: ['eventByUUID'],
 80      });
 81      setIsEditing(false);
 82    } catch (error) {
 83      console.error(error);
 84      addToast(t('event.errors.cant_update'));
 85    }
 86  };
 87
 88  const canAddSelf = useMemo(() => {
 89    if (!user) return false;
 90    const isInWaitingList = event?.waitingPassengers?.some(
 91      passenger => passenger.user?.id === `${user.id}`
 92    );
 93    const isInTravel = event?.travels.some(travel =>
 94      travel.passengers.some(passenger => passenger.user?.id === `${user.id}`)
 95    );
 96    return !(isInWaitingList || isInTravel);
 97  }, [event, user]);
 98
 99  if (!event || loading) return <Loading />;
100
101  return (
102    <Layout
103      className={classes.layout}
104      pageTitle={t('event.title', {title: event.name})}
105      menuTitle={t('event.title', {title: event.name})}
106      displayMenu={false}
107    >
108      <EventBar event={event} onAdd={setIsAddToMyEvent} onSave={onSave} />
109      <DrawerMenu />
110      <WaitingList
111        canAddSelf={canAddSelf}
112        getToggleNewPassengerDialogFunction={(addSelf: boolean) => () =>
113          toggleNewPassengerToWaitingList({addSelf})}
114      />
115      <AddToMyEventDialog
116        event={event}
117        open={isAddToMyEvent}
118        onClose={() => setIsAddToMyEvent(false)}
119      />
120      {!!addPassengerToWaitingListContext && (
121        <AddPassengerToWaitingList
122          open={!!addPassengerToWaitingListContext}
123          toggle={() => toggleNewPassengerToWaitingList(null)}
124          addSelf={addPassengerToWaitingListContext.addSelf}
125        />
126      )}
127    </Layout>
128  );
129};
130
131export async function getServerSideProps(ctx) {
132  const {uuid} = ctx.query;
133  const apolloClient = initializeApollo();
134  const {data = {}} = await apolloClient.query({
135    query: EventByUuidDocument,
136    variables: {uuid},
137  });
138  const {eventByUUID: event} = data;
139  const {host = ''} = ctx.req.headers;
140
141  return {
142    props: {
143      event,
144      eventUUID: uuid,
145      metas: {
146        title: event?.name || '',
147        url: `https://${host}${ctx.resolvedUrl}`,
148      },
149    },
150  };
151}
152
153const useStyles = makeStyles(theme => ({
154  layout: ({bannerOffset}) => ({
155    paddingTop: theme.mixins.toolbar.minHeight + bannerOffset,
156  }),
157}));
158
159export default EventPage;